import { ref, computed } from 'vue';
import { defineStore } from 'pinia'; //defineStore这个函数用于定义储存方法


const USER_KEY = "OA_USER_KEY";  //两个常量用于在 localStorage 中存储用户信息和 token 的键名。
const TOKEN_KEY = "OA_TOKEN_KEY";

//定义权限级别：用二进制
export const PermissionChoices = { 
  All:0b111, //所有权限
  Staff:0b000, //普通员工权限
  Boarder:0b001, //董事会权限
  Leader:0b010, //部门老大权限
}

//定义了一个名为 useAuthStore 的 Pinia 存储，它被导出，以便在应用程序的其他部分中使用
export const useAuthStore = defineStore('auth', () => { //第一个参数是存储的名称auth，第二个参数是一个函数，该函数返回存储的值。
  let _user = ref({});   // 加上_表示私有变量，不允许外界访问  
  let _token = ref("");  //ref代表实时监听属性

  function setUserToken(user, token) {
    // 保存到对象上（内存中）
    _user.value = user;
    _token.value = token;
    // 存储到浏览器的localStorage（硬盘中）
    localStorage.setItem(USER_KEY, JSON.stringify(user)); // 只能存储字符串，user是一个对象所以需要转换为json格式
    localStorage.setItem(TOKEN_KEY, JSON.stringify(token));
  }

  function clearUserToken(){
    _user.value = {}
    _token.value = {}
    localStorage.removeItem(USER_KEY)
    localStorage.removeItem(TOKEN_KEY)
  }

  // 计算属性
  let user = computed(() => {  //computed表示一个计算属性
    // _user为空对象（内存中没有），那就从localStorage中获取
    //_user.value = {}  =>Object.keys(_user.value).length==0 :该方法会返回对象所有键的一个数组，通过判断数组长度来检查对象是否为空
    //在js中 空对象{}：用if判断 会返回true     
    //       空字符串"" 用if判断会返回false
    if (Object.keys(_user.value).length==0) {
      let user_str = localStorage.getItem(USER_KEY)//内存中没有就从硬盘中获取并赋值
      if(user_str){  //不为空的情况
        _user.value = JSON.parse(user_str) //解析为json对象保存
      }
    }
    return _user.value; // 内存中有就直接返回
  });

  let token = computed(() => {
    // _token为空对象（内存中没用），那就从localStorage中获取
    if (!_token.value) {
      let token_str = localStorage.getItem(TOKEN_KEY)
      if(token_str){
        _token.value = token_str
      }
    }
    return _token.value; // 内存中有就直接返回
  });

  let is_logined = computed(() =>{  //定义变量用于导航守卫判断是否登陆
    //将上面定义的计算属性user作为判断条件，这样会自动执行上面的user定义，防止浏览器关闭后该值为空
    if(Object.keys(user.value).length>0 && token.value){
      return true;
    }
    return false;
  })
  
  //返回用户所拥有权限
  let own_permissions = computed(() => {
    // 0b000
    let _permissions = PermissionChoices.Staff //默认是普通员工权限
    if(is_logined.value){ //已登录情况
      // 判断是否是董事会成员
      if(user.value.department.name == '董事会'){
      //使用按位与运算来合并权限   0b000 | 0b001 = 0b001
        _permissions |= PermissionChoices.Boarder
      }

      // 判断是否是team leader
      if(user.value.department.leader_id == user.value.uid){
        _permissions |= PermissionChoices.Leader
      }
    }
    return _permissions
  })

  //检查用户是否有指定权限
  function has_permission(permissions, opt='|'){
    // opt可选值：   1. |：或运算  2. &：且运算
    // own_permissions: 0b001
    // permissions: [0b010, 0b001]

    let results = permissions.map((permission) => (permission&own_permissions.value)==permission) //检查权限值是否在用户权限中
    // results = [true, false, false, true]
    if(opt == "|"){
      if(results.indexOf(true) >= 0){
        return true;
      }else{
        return false;
      }
    }else{
      if(results.indexOf(false) >= 0){
        return false;
      }else{
        return true
      }
    }
  }
  

  // 为了让外界访问到，必须要返回 返回了对象，包含 setUserToken 函数和计算属性 user、token
  return { setUserToken, user, token,is_logined,clearUserToken,has_permission };
});
